﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using INFDTM01.Models;

namespace INFDTM01.Services
{
    public class UserPredictionService
    {
        public RatingDifferenceCollection _DiffMarix = new RatingDifferenceCollection();  // The dictionary to keep the diff matrix
        public HashSet<int> _Items = new HashSet<int>();  // Tracking how many items totally

        public void AddUserRatings(Dictionary<int, float> userRatings)
        {
            foreach (var item1 in userRatings)
            {
                int item1Id = item1.Key;
                float item1Rating = item1.Value;
                _Items.Add(item1.Key);

                foreach (var item2 in userRatings)
                {
                    if (item2.Key <= item1Id) continue; // Eliminate redundancy
                    int item2Id = item2.Key;
                    float item2Rating = item2.Value;

                    Rating ratingDiff;
                    if (_DiffMarix.Contains(item1Id, item2Id))
                    {
                        ratingDiff = _DiffMarix[item1Id, item2Id];
                    }
                    else
                    {
                        ratingDiff = new Rating();
                        _DiffMarix[item1Id, item2Id] = ratingDiff;
                    }

                    ratingDiff.Value += item1Rating - item2Rating;
                    ratingDiff.Freq += 1;
                }
            }
        }

        public Dictionary<int, float> Predict(Dictionary<int, UserPreference> userPreferences, int userId)
        {
            Dictionary<int, float> userRatings = new Dictionary<int,float>();

            foreach (KeyValuePair<int, UserPreference> pair in userPreferences)
            {
                if (pair.Key != userId)
                {
                    userRatings = new Dictionary<int, float>();

                    for (int i = 0; i < pair.Value.ItemIds.Length; i++)
                    {
                        userRatings.Add(pair.Value.ItemIds[i], pair.Value.Preferences[i]);
                    }

                    AddUserRatings(userRatings);
                }
            }

            userRatings = new Dictionary<int, float>();
            UserPreference user = userPreferences[userId];

            for (int i = 0; i < user.ItemIds.Length; i++)
            {
                userRatings.Add(user.ItemIds[i], user.Preferences[i]);
            }

            Dictionary<int, float> Predictions = new Dictionary<int, float>();

            foreach (var itemId in this._Items)
            {
                if (userRatings.Keys.Contains(itemId)) continue; // User has rated this item, just skip it

                Rating itemRating = new Rating();

                foreach (var userRating in userRatings)
                {
                    if (userRating.Key == itemId) continue;
                    int inputItemId = userRating.Key;
                    if (_DiffMarix.Contains(itemId, inputItemId))
                    {
                        Rating diff = _DiffMarix[itemId, inputItemId];
                        itemRating.Value += diff.Freq * (userRating.Value + diff.AverageValue * ((itemId < inputItemId) ? 1 : -1));
                        itemRating.Freq += diff.Freq;
                    }
                }
                Predictions.Add(itemId, itemRating.AverageValue);
            }

            return Predictions;
        }
    }
}